'''
代聪聪
第三类客户：快递员
=================================================
2022.5.13
快递员客户的登录、注册、修改信息
与第一类用户相比，不同点:
1、与SS连接的时候port不同：port_ss_deliver = 15032

=================================================
'''

import tkinter as tk
import tkinter.messagebox
from tkinter import *
from tkinter import ttk
import socket
import threading

import des2
import hash
from packet import get_pack  # 用来打包
from packet import pack  # 用来解析报文
import time
import config
import mysocket

#  主界面
#  =========================================================


main_win = tk.Tk()
main_win.title('快递员管理系统')
main_win.geometry('500x400')
main_win.withdraw()  # 隐藏

#  登陆界面
#  =========================================================
login_win = tk.Toplevel(main_win)  # 在主界面的上层显示
login_win.title('用户登录')
login_win.geometry('350x350+300+300')

#  登录：用户id、密码  在最外层  _lg代表登陆时的用户输入
tk.Label(login_win, text='用户ID').place(x=60, y=100)
id_lg = tk.Entry(login_win)
id_lg.place(x=130, y=100)

tk.Label(login_win, text='密  码').place(x=60, y=150)
password_lg = tk.Entry(login_win, show='*')
password_lg.place(x=130, y=150)


# 登录按钮实现，也在最外层
def log():
    id1 = id_lg.get()
    password1 = password_lg.get()
    password1_en = hash.encrypt(password1)
    # 连接AS服务器获取tgt
    s_as = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    buffer_size = 1024
    address_as = (config.addr_as, config.port_as)
    # 开始连接AS服务器
    s_as.connect(address_as)
    while True:
        ts1 = time.time()
        info2as = {"idc": id1, "passwd": password1_en, "id_tgs": 'tgs', "ts1": ts1}
        msg2as = get_pack('c_a', 'deliver', 'get_ticket1', content=str(info2as))  # AS认证不需要检查
        s_as.send(msg2as)
        msg2as_re = mysocket.recv(s_as)
        content_plain = des2.decrypt(msg2as_re.content, password1_en)
        content_dic = dict(eval(content_plain))
        tgt = content_dic['tgt']
        if tgt is not None:
            tk.messagebox.showinfo(title='成功', message='请求AS认证成功')
            break
        else:
            tk.messagebox.showinfo(title='错误', message='请求AS认证失败')

    s_as.close()  # 关闭与AS连接的socket
    print('as认证结束')

    #  用tgt向TGS服务器获取st
    s_tgs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    address_tgs = (config.addr_tgs, config.port_tgs)
    #  开始连接TGS服务器
    s_tgs.connect(address_tgs)
    while True:
        kc_tgs = int(content_dic["kc_tgs"])
        ts3 = time.time()
        lifetime = '480'
        authenticator = {"idc": id1, "ad_c": '', "ts_3": ts3, "Lifetime": lifetime}
        authenticator_c = des2.encrypt(str(authenticator), kc_tgs)
        info2tgs = {"idv": '', "tgt": tgt, "Authenticator_c": authenticator_c}
        msg2tgs = get_pack('c_t', 'deliver', 'request_ticket2', content=str(info2tgs))  # 这里C向TGS发送的消息
        mysocket.send(s_tgs, msg2tgs)
        msg2tgs_re = mysocket.recv(s_tgs)
        content2_plain = des2.decrypt(msg2tgs_re.content, kc_tgs)
        content2_dic = dict(eval(content2_plain))
        st = content2_dic["ticket"]
        if st is not None:
            # tk.messagebox.showinfo(title='成功', message='请求TGS票据成功')
            break
        else:
            tk.messagebox.showinfo(title='错误', message='请求TGS票据失败')

    s_tgs.close()

    #  用ST向V请求登录
    s_ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    address_ss = (config.addr_ss, config.port_ss_deliver)
    s_ss.connect(address_ss)  # 连上
    while True:
        kc_v = int(content2_dic['kc_v'])  # 强制类型转换成了int
        private_key_ss = str(content2_dic["private_key"])
        ts5 = time.time()
        _authenticator2s = {"id_c": id1, "ad_c": '', "ts_5": ts5}
        authenticator2s = des2.encrypt(str(_authenticator2s), kc_v)
        info2ss = {"ticket": st, "Authenticator_c": authenticator2s}
        msg2ss = get_pack('c_s', sign='deliver', control_type='message5', content=str(info2ss))
        mysocket.send(s_ss, msg2ss)  # 分片发送
        msg2ss_re = mysocket.recv(s_ss)  # 分片接收
        _content3 = des2.decrypt(msg2ss_re.content, kc_v)
        content3_dic = dict(eval(_content3))
        ts6 = content3_dic['ts6']
        pk_v = content3_dic['pk_v']
        print('pk_v: ', type(pk_v), pk_v)
        if ts6 == ts5 + 1:
            tk.messagebox.showinfo(title='成功', message='登录成功')
            # s_ss.close()
            # mysocket.send(s_ss, msg2ss)
            break
        else:
            tk.messagebox.showinfo(title='失败', message='登录失败')
            break

    login_win.withdraw()  # 摧毁登陆界面
    main_win.deiconify()  # 显示主界面

    #  功能界面功能1——修改信息
    def modify_info():
        mod_win = tk.Toplevel(main_win)
        mod_win.title('修改快递员信息界面')
        mod_win.geometry('200x250+200+200')

        # 输入框
        tk.Label(mod_win, text='ID(不可更改)').place(x=20, y=20)
        tk.Label(mod_win, text=id1).place(x=100, y=20)

        tk.Label(mod_win, text='修改姓名').place(x=20, y=65)
        name_md = tk.Entry(mod_win)
        name_md.place(x=100, y=65)

        tk.Label(mod_win, text='修改性别').place(x=20, y=110)
        sex_md = tk.Entry(mod_win)
        sex_md.place(x=100, y=110)

        tk.Label(mod_win, text='修改号码').place(x=20, y=165)
        tp_md = tk.Entry(mod_win)
        tp_md.place(x=100, y=165)

        def ok_mod():
            name_m = name_md.get()  # 商店名称
            sex_m = sex_md.get() #
            tp_m = tp_md.get()  # 商店号码

            mdinfo_req = {"id": id1, "name": name_m, "sex": sex_m,  "phonenumber": tp_m}
            mypacket = get_pack('c_s', 'deliver', 'modify_info', content=str(mdinfo_req),
                                sessionkey=kc_v, privatekey=private_key_ss)
            mysocket.send(s_ss, mypacket)
            mdinfo_re = mysocket.recv(s_ss, sessionkey=kc_v, publickey=pk_v)
            # _content4 = pack(mdinfo_re, sessionkey=kc_v, publickey=pk_v)
            if int(mdinfo_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='信息修改失败')
            else:
                tk.messagebox.showinfo(title='成功', message='信息修改成功')

                mod_win.destroy()  # 销毁修改信息页面

            # 确定按钮，触发修改功能
        tk.Button(mod_win, text='确认修改', command=ok_mod).place(x=100, y=205)

    def salary():
        sly_win = tk.Toplevel(main_win)
        sly_win.title('工资提现')
        sly_win.geometry('300x150+200+200')

        tk.Label(sly_win, text='密码').place(x=25, y=20)
        sly_pwd = tk.Entry(sly_win, show='*')
        sly_pwd.place(x=100, y=20)

        tk.Label(sly_win, text='金额').place(x=25, y=65)
        sly_money = tk.Entry(sly_win, show='*')
        sly_money.place(x=100, y=65)

        def ok_sly():
            # 按钮触发发送请求功能
            pwd_d = sly_pwd.get()
            money_d = sly_money.get()

            sly_req = {"id": id1, "passwd": pwd_d, "money": money_d}
            mypacket = get_pack('c_s', 'deliver', 'cash_out', content=str(sly_req), sessionkey=kc_v,
                                privatekey=private_key_ss)
            mysocket.send(s_ss, mypacket)
            sly_re = mysocket.recv(s_ss, sessionkey=kc_v, publickey=pk_v)
            if int(sly_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='工资提现提现失败')
            else:
                tk.messagebox.showinfo(title='成功', message='工资提现提现成功')
                tk.Label(main_win,text=sly_re.content).place(x=450, y=60)

        tk.Button(sly_win, text='确认提现',command=ok_sly).place(x=100, y=110)

    def click_change():
        # 一键上下班
        chge_req = {"id": id1}
        mypacket = get_pack('c_s', 'deliver', 'one_click_commuting', content=str(chge_req),
                            sessionkey=kc_v, privatekey=private_key_ss)
        mysocket.send(s_ss, mypacket, ack_flag=False)

        chge_re = mysocket.recv(s_ss, sessionkey=kc_v, publickey=pk_v)
        if int(chge_re.state) != 1:
            tk.messagebox.showinfo(title='错误', message='上班状态修改失败')
        else:
            tk.messagebox.showinfo(title='成功', message='上班状态修改成功')
            tk.Label(main_win, text=chge_re.content).place(x=480, y=150)


    tk.Button(main_win, text='修改信息', command=modify_info).place(x=420, y=20)
    tk.Button(main_win, text='工资提现', command=salary).place(x=420, y=60)
    tk.Button(main_win, text='上/下班', command=click_change).place(x=420, y=100)



#  注册界面
#  ==================================================
#  注册按钮，唤醒一个新的顶部界面
def reg():
    #  注册窗口
    reg_win = tk.Toplevel(login_win)
    reg_win.title('快递员注册界面')
    reg_win.geometry('300x300+200+200')
    """
            骑手注册
            :param id:骑手id
            :param password1:骑手密码
            :param name: 骑手姓名
            :param sex: 骑手性别
            :param phonenumber: 骑手电话号码
            :param wage: 骑手工资  ？
            :param state: 骑手状态：上班/下班  ？
            :return:
            """
    #  输入框 获得快递员详细信息
    #  输入框 获得商家详细信息
    tk.Label(reg_win, text='骑手ID').place(x=30, y=20)
    id_rg = tk.Entry(reg_win)
    id_rg.place(x=100, y=20)

    tk.Label(reg_win, text='骑手密码').place(x=30, y=65)
    password_rg = tk.Entry(reg_win, show='*')
    password_rg.place(x=100, y=65)

    tk.Label(reg_win, text='骑手名').place(x=30, y=110)
    name_rg = tk.Entry(reg_win)
    name_rg.place(x=100, y=110)

    tk.Label(reg_win, text='骑手性别').place(x=30, y=155)
    sex_rg = tk.Entry(reg_win)
    sex_rg.place(x=100, y=155)

    tk.Label(reg_win, text='骑手电话号码').place(x=30, y=200)
    phone_rg = tk.Entry(reg_win)
    phone_rg.place(x=100, y=200)

    def ok_reg():
        # 获得用户输入 _rg代表注册时的输入信息
        id2 = id_rg.get()
        password2 = password_rg.get()
        pwd2_en = hash.encrypt(password2)
        name2 = name_rg.get()
        sex2 = sex_rg.get()
        phone2 = phone_rg.get()

        # 触发功能按钮

        # 创建socket准备连接AS
        s_as = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        buffer_size = 1024
        address_as = (config.addr_as, config.port_as)
        # 开始连接AS服务器
        s_as.connect(address_as)
        while True:
            info2as = {"id": id2, "passwd": pwd2_en}
            msg2as = get_pack('c_a', 'deliver', 'request_enroll', content=str(info2as))  # 请求注册的消息
            s_as.send(msg2as)
            flag_as = s_as.recv(buffer_size)
            msg2as_re = pack(flag_as)
            if int(msg2as_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='AS注册失败')

            else:
                # tk.messagebox.showinfo(title='成功', message='AS注册成功')
                print('AS注册成功')
                break
        s_as.close()  # 关闭与AS通信的socket

        #  创建socket准备连接SS
        s_ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        address_ss = (config.addr_ss, config.port_ss_deliver)
        s_ss.connect(address_ss)  # 连上

        while True:
            info2ss = {"id": id2, "passwd": pwd2_en, "name": name2, "sex": sex2, "phonenumber": phone2}
            msg2ss = get_pack('c_s', 'deliver', 'signature', content=str(info2ss))  # 请求注册的消息
            s_ss.send(msg2ss)
            flag_ss = s_ss.recv(1024)
            msg2ss_re = pack(flag_ss)
            if int(msg2ss_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='SS注册失败')
                break
            else:
                tk.messagebox.showinfo(title='成功', message='注册成功')
                # print('SS注册成功')
                break

        s_ss.close()  # 关闭与SS通信的socket

        reg_win.destroy()  # 关闭注册界面

    tk.Button(reg_win, text='确定', command=ok_reg).place(x=245, y=250)

#  修改信息界面
#  =======================================================
def alt_pwd():
    alt_win = tk.Toplevel(login_win)
    alt_win.title('修改快递员信息')
    alt_win.geometry('300x300+200+200')

    #  输入框， 输入旧密码和新密码，
    tk.Label(alt_win, text='ID(不可更改)').place(x=25, y=20)
    id_alt = tk.Entry(alt_win)
    id_alt.place(x=100, y=20)

    tk.Label(alt_win, text='旧密码').place(x=25, y=65)
    password_alt = tk.Entry(alt_win)
    password_alt.place(x=100, y=65)

    tk.Label(alt_win, text='新密码').place(x=25, y=110)
    re_pwd_alt = tk.Entry(alt_win)
    re_pwd_alt.place(x=100, y=110)

    def ok_alt():
        # 获取用户输入 re_ 为修改后的信息
        id3 = id_alt.get()
        pwd3 = password_alt.get()
        pwd3_en = hash.encrypt(pwd3)  # hash加密后的密码
        re_pwd = re_pwd_alt.get()
        re_pwd_en = hash.encrypt(re_pwd)

        # 触发功能按钮

        # 创建socket准备连接AS
        s_as = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        buffer_size = 1024
        address_as = (config.addr_as, config.port_as)
        # 开始连接AS服务器
        s_as.connect(address_as)
        while True:
            info2as = {"id": id3, "passwd_old": pwd3_en, "passwd_new": re_pwd_en}
            msg2as = get_pack('c_a', 'deliver', 'modify_pwd', content=str(info2as))  # 请求修改的消息
            s_as.send(msg2as)
            flag_as = s_as.recv(buffer_size)
            msg_re = pack(flag_as)
            if int(msg_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='AS信息更改失败')
            else:
                # tk.messagebox.showinfo(title='成功', message='AS信息更改成功')
                print('AS信息更改成功')
                break
        s_as.close()  # 关闭与AS通信的socket

        # 创建socket准备连接SS
        s_ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        address_ss = (config.addr_ss, config.port_ss_store)
        #  开始连接SS
        s_ss.connect(address_ss)
        while True:
            info2ss = {"id": id3, "passwd_new": pwd3_en, "passwd_old": re_pwd_en}
            msg2ss = get_pack('c_s', 'deliver', 'modify_pwd', content=str(info2ss))  # 请求修改的消息
            s_ss.send(msg2ss)
            flag_ss = s_ss.recv(buffer_size)
            msg_re = pack(flag_ss)
            if int(msg_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='信息更改失败')
                break
            else:
                tk.messagebox.showinfo(title='成功', message='信息更改成功')
                print('SS修改信息成功')
                break

        s_ss.close()  # 关闭与SS通信的socket

        alt_win.destroy()  # 销毁修改信息窗口


    # 按钮布置，确定 唤起功能按钮
    tk.Button(alt_win, text='确定', command=ok_alt).place(x=240, y=250)



#  按钮布置：登录、注册、修改信息  在最外层
tk.Button(login_win, text='登录', command=log).place(x=80, y=200)
tk.Button(login_win, text='注册', command=reg).place(x=160, y=200)
tk.Button(login_win, text='修改密码', command=alt_pwd).place(x=240, y=200)


#  运行
if __name__ == '__main__':
    main_win.mainloop()
